package com.yi.mall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.yi.mall.api.CartFeign;
import com.yi.mall.api.SkuInfoFeign;

import com.yi.mall.common.model.Cart;
import com.yi.mall.common.model.DTO.StockDTO;
import com.yi.mall.common.model.DTO.orderDTO;
import com.yi.mall.common.model.OrderDetail;
import com.yi.mall.common.model.OrderInfo;
import com.yi.mall.common.model.OrderQuery;
import com.yi.mall.common.utils.Result;


import com.yi.mall.order.service.IOrderDetailService;
import com.yi.mall.order.service.IOrderInfoService;
import com.yi.mall.order.service.IOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;


import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@GlobalTransactional(rollbackFor = Exception.class)
public class OrderServiceImpl implements IOrderService {
    @Qualifier("com.yi.mall.api.SkuInfoFeign")
    @Autowired
    private SkuInfoFeign skuInfoFeign;
    @Qualifier("com.yi.mall.api.CartFeign")
    @Autowired
    private CartFeign cartFeign;
    @Autowired
    private IOrderInfoService orderInfoService;
    @Autowired
    private IOrderDetailService orderDetailService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StreamBridge streamBridge;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderInfo save(orderDTO orderVO) throws Exception {
        // 生成订单编号
        String orderId = IdWorker.getIdStr();
        // 分解参数
        List<OrderDetail> orderDetails = orderVO.getOrderDetails();
        List<String> cartIds = orderVO.getCartIds();
        // 1 保存订单详情
        // 1.1 设置各商品的订单编号和合计金额
        List<OrderDetail> details = orderDetails.stream().map(e -> {
            e.setOrderId(orderId);// 设置订单
            // 设置合计金额
            BigDecimal amount = e.getPrice().multiply(new BigDecimal(e.getQuantity()));
            e.setAmount(amount);
            return e;
        }).collect(Collectors.toList());
        // 1.2 保存订单详情
        orderDetailService.saveBatch(details);
        // 2 保存订单
        // 2.1 计算订单总金额
        BigDecimal totalAmount = new BigDecimal(0);
        for (OrderDetail detail : details) {
            totalAmount = totalAmount.add(detail.getAmount());
        }
        // 2.2 创建订单对象
        OrderInfo orderInfo = JSON.parseObject(JSON.toJSONString(orderVO), OrderInfo.class);
        orderInfo.setOrderId(orderId);
        orderInfo.setTotalAmount(totalAmount);
        // 2.3 保存订单
        orderInfoService.save(orderInfo);
        // 3 递减库存
        //我们现在有购物车id集合，一个购物车对应一个商品，里面有商品的数量和库存的id
        //递减库存需要stockdto，里面有两个属性，一个库存id一个要扣减的数量
        //所以现在我们需要遍历id集合查找出所有购物车集合
        //再从购物车集合里拿出我们需要的skuid和num转换成stockdto
        //最后远程调用把stockdto集合传进去完成递减库存
        // 3.1 构建购物车集合
        List<String> cartIds1 = orderVO.getCartIds();
        List<Cart> cartlist = cartIds1.stream().map((cartid) -> {
            Result byid = cartFeign.findByid(cartid);
            Cart cart = JSON.parseObject(JSON.toJSONString(byid.getData()), Cart.class);
            return cart;
        }).collect(Collectors.toList());
        List<StockDTO> collect = cartlist.stream()
                .filter(Objects::nonNull)
                .map((cart) -> {
            StockDTO stockDTO = new StockDTO();
            stockDTO.setSkuId(cart.getSkuId());
            stockDTO.setNum(cart.getNum());
            return stockDTO;
        }).collect(Collectors.toList());
        // 3.2 递减库存-远程调用
        Result result = skuInfoFeign.dcount(collect);

        if (result.getCode() != 2000) {
            throw new Exception(result.getMessage());
        }
        //删除购物车需要购物车id集合，我们这里已经有了
        //直接远程调用传参进去
        // 4 删除购物车
        // 4.1 构建购物车集合
        // 4.2 删除购物车-远程调用
        cartFeign.rmall(cartIds1);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                Message<?> message = MessageBuilder
                        .withPayload(JSON.toJSONString(cartIds))
                        // 以orderId作为事务Id发送消息
                        .setHeader("TRANSACTION_ID",orderId).build();
                streamBridge.send("deleteCart-out-0",message);
            }
        });
        // 5.下单回查
        // 5.1 以orderId和userId去重
        String id = orderId + orderInfo.getUserId();
        // 5.2 发送支付回查请求
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                Message<?> message = MessageBuilder
                        .withPayload(orderId)
                        .setHeader("TRANSACTION_ID", orderId)
                        .setHeader("DELAY", "9") // 使用官方 Header
                        .build();

                if (redisTemplate.opsForValue().setIfAbsent("REQ_" + id, "1", 60, TimeUnit.SECONDS)) {
                    streamBridge.send("checkPayOutput-out-0", message);
                }
            }
        });

        return orderInfo;
        }
    @Override
    public Page page(OrderQuery query) {
        // 1. 查询订单信息
        Page page = orderInfoService.page(query);
        /*
         * 如果查询结果不为空，获取订单数据
         */
        if(page.getTotal() > 0){
            // 获取订单数据
            List<OrderInfo> records = page.getRecords();
            List<String> ids = records.stream().map(OrderInfo::getOrderId).collect(Collectors.toList());
            // 获取所有订单的详情
            List<OrderDetail> details = orderDetailService.listByOrderIds(ids);

            List<orderDTO> data = records.stream().map(orderInfo -> {
                // 筛选每个订单的订单详情
                List<OrderDetail> collect = details.stream().filter(orderDetail -> orderDetail.getOrderId().equals(orderInfo.getOrderId()))
                        .collect(Collectors.toList());
                // 将OrderInfo转换成OrderDTO
                orderDTO orderDTO = JSON.parseObject(JSON.toJSONString(orderInfo), orderDTO.class);
                orderDTO.setOrderDetails(collect);
                return orderDTO;
            }).collect(Collectors.toList());
            // 封装页面数据
            page.setRecords(data);
            return page;
        }
        return null;
    }
    public void removeById(Long id) {
        orderInfoService.removeById(id);
        orderDetailService.removeByOrderId(id);
    }

}
